package com.habitrpg.android.habitica.ui.views.ads

import android.content.Context
import android.util.AttributeSet
import android.view.Gravity
import android.view.View
import android.widget.LinearLayout
import androidx.core.content.ContextCompat
import androidx.lifecycle.LifecycleCoroutineScope
import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.databinding.AdButtonBinding
import com.habitrpg.android.habitica.extensions.getMinuteOrSeconds
import com.habitrpg.android.habitica.extensions.getShortRemainingString
import com.habitrpg.android.habitica.helpers.AdHandler
import com.habitrpg.android.habitica.helpers.AdType
import com.habitrpg.common.habitica.extensions.layoutInflater
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import java.util.Date
import kotlin.time.DurationUnit
import kotlin.time.toDuration

class AdButton
@JvmOverloads
constructor(
    context: Context,
    attrs: AttributeSet? = null
) : LinearLayout(context, attrs) {
    var state: State = State.READY
        set(value) {
            field = value
            updateViews()
        }

    enum class State {
        EMPTY,
        READY,
        LOADING,
        UNAVAILABLE
    }

    private var updateJob: Job? = null
    private var nextAdDate: Date? = null
    private val binding = AdButtonBinding.inflate(context.layoutInflater, this)

    private var activeBackgroundRes: Int = R.drawable.ad_button_background

    var text: String = ""
        set(value) {
            field = value
            updateViews()
        }

    init {
        context.theme?.obtainStyledAttributes(
            attrs,
            R.styleable.AdButton,
            0,
            0
        )?.let { attributes ->
            text = attributes.getString(R.styleable.AdButton_text) ?: ""
            binding.currencyView.currency = attributes.getString(R.styleable.AdButton_currency)
            activeBackgroundRes =
                attributes.getResourceId(
                    R.styleable.AdButton_activeBackground,
                    R.drawable.ad_button_background
                )
            binding.textView.setTextColor(
                attributes.getColor(
                    R.styleable.AdButton_textColor,
                    ContextCompat.getColor(context, R.color.white)
                )
            )
        }
        binding.currencyView.setTextColor(ContextCompat.getColor(context, R.color.white))
        binding.currencyView.value = 0.0
        if (binding.currencyView.currency?.isNotBlank() != true) {
            binding.currencyView.visibility = View.GONE
        }
        gravity = Gravity.CENTER
        state = State.READY
    }

    private fun updateViews() {
        when (state) {
            State.READY -> {
                binding.loadingIndicator.visibility = GONE
                binding.textView.text = text
                binding.textView.alpha = 1.0f
                binding.textView.visibility = VISIBLE
                binding.currencyView.visibility = VISIBLE
                setBackgroundResource(activeBackgroundRes)
            }

            State.UNAVAILABLE -> {
                binding.loadingIndicator.visibility = GONE
                binding.textView.text =
                    context.getString(
                        R.string.available_in,
                        nextAdDate?.getShortRemainingString() ?: ""
                    )
                binding.textView.alpha = 0.75f
                binding.textView.visibility = VISIBLE
                binding.currencyView.visibility = GONE
                setBackgroundResource(R.drawable.ad_button_background_disabled)
            }

            State.EMPTY -> {
                binding.loadingIndicator.visibility = GONE
                binding.textView.visibility = GONE
                binding.currencyView.visibility = GONE
            }

            State.LOADING -> {
                binding.loadingIndicator.visibility = VISIBLE
                binding.textView.visibility = GONE
                binding.currencyView.visibility = GONE
            }
        }
        isEnabled = state == State.READY
    }

    fun updateForAdType(
        type: AdType,
        lifecycleScope: LifecycleCoroutineScope
    ) {
        if (updateJob?.isActive == true) {
            updateJob?.cancel()
        }
        nextAdDate = AdHandler.nextAdAllowedDate(type)
        if (nextAdDate?.after(Date()) == true) {
            updateJob =
                lifecycleScope.launch(Dispatchers.Main) {
                    while (nextAdDate?.after(Date()) == true) {
                        val remaining =
                            (
                                (
                                    nextAdDate?.time
                                        ?: 0L
                                    ) - Date().time
                                ).toDuration(DurationUnit.MILLISECONDS)
                        state = if (remaining.isNegative()) State.READY else State.UNAVAILABLE
                        updateViews()
                        delay(1.toDuration(remaining.getMinuteOrSeconds()))
                    }
                    state = State.READY
                }
        }
    }
}
